{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bd8fefa4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('Hello, ', 'name', '', None)\n",
      "('! You are ', 'age', '', None)\n",
      "(' years old.', None, None, None)\n"
     ]
    }
   ],
   "source": [
    "# python 的Formatter 用来解析格式的。\n",
    "from string import Formatter\n",
    "\n",
    "# 定义一个简单模板\n",
    "template = \"Hello, {name}! You are {age} years old.\"\n",
    "\n",
    "\"\"\"\n",
    "formatter.parse(template) 的输出是一个迭代器，转换为列表后包含 3 个元组，每个元组的结构为：(literal_text, field_name, format_spec, conversion)\n",
    "各字段含义如下：\n",
    "literal_text：当前占位符之前的普通文本（非占位符部分）。\n",
    "field_name：占位符的名称（如 name、age），若没有占位符则为 None。\n",
    "format_spec：占位符的格式说明（如 {age:.2f} 中的 .2f），无格式时为 ''。\n",
    "conversion：占位符的转换符（如 {name!r} 中的 r），无转换时为 ''。\n",
    "\"\"\"\n",
    "# 解析模板\n",
    "formatter = Formatter()\n",
    "parsed_result = list(formatter.parse(template))  # 转换为列表便于查看\n",
    "\n",
    "# 打印解析结果\n",
    "for item in parsed_result:\n",
    "    print(item)\n",
    "# 第一个元组：literal_text 为空（占位符 {name} 前无文本），field_name 是 name\n",
    "# 第二个元组：literal_text 是 ! You are （{name} 和 {age} 之间的文本），field_name 是 age\n",
    "# 第三个元组：literal_text 是 years old.（{age} 后的文本），无占位符（field_name 为 None）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "545ce6f1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('Price: ', 'price', '.2f', None)\n",
      "(', Score: ', 'score', '>5d', None)\n",
      "(', Date: ', 'date', '%Y-%m-%d', None)\n"
     ]
    }
   ],
   "source": [
    "from string import Formatter\n",
    "\n",
    "# 模板中包含带格式说明的占位符\n",
    "template = \"Price: {price:.2f}, Score: {score:>5d}, Date: {date:%Y-%m-%d}\"\n",
    "\n",
    "formatter = Formatter()\n",
    "parsed_result = list(formatter.parse(template))\n",
    "\n",
    "# 打印解析结果\n",
    "for item in parsed_result:\n",
    "    print(item)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9c83955",
   "metadata": {},
   "source": [
    "具体含义如下：\n",
    "\n",
    "第一个元组 ('Price: ', 'price', '.2f', None)\n",
    "\n",
    "field_name: 'price'：占位符名称是 price。\n",
    "\n",
    "format_spec: '.2f'：格式说明为保留 2 位小数的浮点数（例如将 3.1415 格式化为 3.14）。\n",
    "\n",
    "第二个元组 (', Score: ', 'score', '>5d', None)\n",
    "\n",
    "field_name: 'score'：占位符名称是 score。\n",
    "\n",
    "format_spec: '>5d'：格式说明为 “右对齐，总宽度 5 位的整数”（例如将 95 格式化为 95，前面补 3 个空格）。\n",
    "\n",
    "第三个元组 (', Date: ', 'date', '%Y-%m-%d', None)\n",
    "\n",
    "field_name: 'date'：占位符名称是 date（通常为 datetime 对象）。\n",
    "\n",
    "format_spec: '%Y-%m-%d'：格式说明为日期格式化字符串（例如将 datetime(2023, 10, 1) 格式化为 2023-10-01）。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "30420bbd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "格式化结果： Price: 30.00, Score:    88, Date: 2023-12-31\n"
     ]
    }
   ],
   "source": [
    "# 要填充的数据\n",
    "from datetime import datetime\n",
    "data = {\n",
    "    \"price\": 29.995,    # 浮点数，需保留2位小数\n",
    "    \"score\": 88,        # 整数，需右对齐且总宽度5位\n",
    "    \"date\": datetime(2023, 12, 31)  # 日期，需格式化为YYYY-MM-DD\n",
    "}\n",
    "\n",
    "# 1. 使用Formatter格式化\n",
    "formatter = Formatter()\n",
    "result1 = formatter.format(template, **data)\n",
    "\n",
    "# 2. 也可以直接用字符串的format方法（效果相同）\n",
    "result2 = template.format(** data)\n",
    "\n",
    "print(\"格式化结果：\", result1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3aed5969",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['name', 'count', 'price']\n"
     ]
    }
   ],
   "source": [
    "from string import Formatter\n",
    "# 自己整一个\n",
    "def get_template_variables(template):\n",
    "    variables = []\n",
    "    for _, field_name, _, _ in Formatter().parse(template):\n",
    "        if field_name is not None:\n",
    "            variables.append(field_name.strip())  # 去除空格\n",
    "    return variables\n",
    "\n",
    "template = \"Hello {name}, your {count} items cost ${price:.2f}\"\n",
    "print(get_template_variables(template))  # 输出：['name', 'count', 'price']"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-course (3.10.12)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
